Skip to content

fix(json-chat): suppress empty-state flash while entries are loading - #84

Merged
frenchie4111 merged 2 commits into
mainfrom
json-chat-suppress-empty-state-flash
May 25, 2026
Merged

fix(json-chat): suppress empty-state flash while entries are loading#84
frenchie4111 merged 2 commits into
mainfrom
json-chat-suppress-empty-state-flash

Conversation

@frenchie4111

Copy link
Copy Markdown
Collaborator

Summary

  • When opening a Chat tab with prior history, the bright What are we going to build today? sparkle empty-state would flash for a frame between mount and the lazy getJsonClaudeEntries fetch landing — the wire snapshot ships sessions with stripped entries (see stripJsonClaudeEntries), and entries.length === 0 && !busy was indistinguishable from "truly empty session" during that window.
  • Add entriesHydrated: boolean to JsonClaudeSession. The reducer flips it true on jsonClaude/entriesSeeded (even when the seeded array is empty, so brand-new tabs still show the empty-state). stripJsonClaudeEntries resets it to false alongside emptying entries, with reference identity preserved when no field would actually change.
  • Gate the empty-state JSX in JsonModeChat.tsx on entriesHydrated. During the loading window we render null instead — a spinner's appear-then-disappear would itself be a flash on the typical sub-100ms fetch.

Test plan

  • npm run typecheck
  • npx electron-vite build
  • npx vitest run src/shared/state src/main/json-claude-status-deriver.test.ts (505 tests pass; new tests cover hydrated default, entriesSeeded with empty array, strip reset, strip reference identity)
  • npm run dev: open a Chat tab with existing history — no sparkle-circle flash
  • npm run dev: create a new Chat tab — empty-state still appears once the (empty) entries fetch completes
  • npm run dev: Cmd+R reload on a tab with history — still no flash

🤖 Generated with Claude Code

frenchie4111 and others added 2 commits May 25, 2026 13:04
The wire snapshot ships sessions with stripped entries to keep
initial-load latency bounded; the renderer lazy-fetches per session on
first mount. Between mount and the entriesSeeded dispatch, the empty
condition (entries=[] && !busy) was true, so the bright sparkle empty-
state would render for ~one frame before messages appeared.

Add an entriesHydrated boolean to JsonClaudeSession that the reducer
flips true on entriesSeeded and stripJsonClaudeEntries resets to false.
The renderer gates the empty-state on it, rendering null during the
loading window (a spinner would itself be a flash).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous commit gated the empty-state on `entriesHydrated`, but the
`jsonClaude:getEntries` handler only dispatched `entriesSeeded` when the
session had non-empty entries — so brand-new (truly empty) sessions
never flipped hydrated to true, and the empty-state card never appeared.

Always dispatch when the session exists. The reducer handles the empty
payload fine; the cost is one extra dispatch per new-tab open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@frenchie4111
frenchie4111 merged commit 1634f1d into main May 25, 2026
1 check passed
frenchie4111 added a commit that referenced this pull request May 25, 2026
PR #84 added the entriesHydrated gate to suppress the empty-state flash,
but the gating made the entire ternary return null on a fresh chat mount
(entries=[], !busy, entriesHydrated=false). The scroll container was
left with no firstElementChild, so the useLayoutEffect that attaches the
ResizeObserver — mounted once with empty deps — found nothing to
observe and never re-ran after entries hydrated. From that point on
streaming token deltas grew the content but never triggered the
snap-to-bottom.

Wrap the conditional in a stable min-h-full flex-col div so the RO
always has a firstElementChild. The empty-state's previous min-h-full
referenced the scroll container; with a wrapper in between, switch it
to flex-1 so it fills the wrapper's column and the sparkle card stays
centered.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant